import React, { useState, useEffect } from 'react'
import qs from 'querystring'
import Footer from '../../components/footer/footer'
import md5 from 'blueimp-md5'
import CONFIG from '../../config'
// 检查是否为一个空的对象，类数组，map或者set
import { isEmpty } from 'lodash'
import { Button, Input, message, Popover, Form } from 'antd'
// `RouteComponentProps`是一个对象的类型，其包含了history,location,match的值的类型。
import { RouteComponentProps } from 'react-router-dom'
// DispatchProp是包含dispatch属性的对象的类型
import { connect } from 'react-redux'
// ThunkDispatch是redux-thunk的dispatch函数的泛型接口
import { ThunkDispatch } from 'redux-thunk'
import { AnyAction } from 'redux'
import { randomCode } from '../../utils'
import { LOCAL_STORAGE } from '../../constants'
import api from '../../api'
import { HOME } from '../../router/constants'
import { serviceLogin } from '../../request/user'
import './login.scss'
import {
  setUser,
  githubAuthorization,
  loginByToken,
} from '../../store/actions/user'
import logo from '../../assets/img/common/logo.png'
import {
  PictureOutlined,
  LockOutlined,
  UserOutlined,
  GithubOutlined,
} from '@ant-design/icons'

type ThunkDispatchType = ThunkDispatch<{}, {}, AnyAction>
// LoginProps包含dispatch函数和history、location、match、staticContext（可选）的类型
// { dispatch: ThunkDispatchType} ：对dispatch函数进行（签名）重载
// ThunkDispatchType是redux-thunk的disptach签名
// DispatchProp是react-redux的包含dispatch函数签名的对象
type LoginProps = {
  dispatch: ThunkDispatchType
} & RouteComponentProps

const PopoverContent = (
  <div style={{ padding: '10px 20px 10px 20px' }}>
    <div>本站不开放注册账号，首次登陆请使用GitHub</div>
    <div>登陆后系统将自动注册账号, 密码为123456</div>
  </div>
)

// 随机字符验证码
let captcha = randomCode()

const LOGIN_NAME = window.sessionStorage.getItem(LOCAL_STORAGE.LOGIN_NAME) || ''
// e是事件对象，e.target可以获取到事件对应的元素
function reloadCaptcha(e: any) {
  captcha = randomCode()
  const url = 'https://work.xiejiahe.com/api' + api.getCaptcha + captcha
  e.target.src = url
}
// 从地址栏中获取重定向地址
function getRedirectUrl() {
  const url = qs.parse(location.search).redirectUrl as string
  return url || HOME.HOME_INDEX.path
}
const Login: React.FC<LoginProps> = function ({
  dispatch,
  history,
  location,
}: LoginProps) {
  // 通过 Form.useForm() 创建 form 实例
  const [form] = Form.useForm()
  const [loading, setLoading] = useState(false)
  // const [state, setState] = useState(fn()); // fn() 每次渲染都会被调用
  // const [state, setState] = useState(() => fn()); // fn() 只会被调用一次
  const [redirectUrl] = useState(getRedirectUrl())
  // 提交数据事件
  const handleSubmit = async () => {
    try {
      // 验证表单数据，生成的value是一个键值对对象，key为Form.item组件name属性的值，value为输入的值
      const values = await form.validateFields()
      setLoading(true)
      // 账号密码登录
      serviceLogin({
        // loginName是Form.item的name的值，password、code同理
        loginName: values.loginName.trim(),
        password: md5(values.password.trim()),
        code: values.code.trim(),
      })
        // setLoading(false)不能放在finally里
        // 如果try和catch模块中不存在return语句，那么运行完try和catch模块中的代码后再运行finally中的代码。
        // then里history.replace(redirectUrl)会使当前组件销毁，组件销毁后不能再设置setState
        .then(res => {
          setLoading(false)
          if (res.data.success) {
            dispatch(setUser(res.data.data.userInfo))
            history.replace(redirectUrl)
          }
        })
        .catch(() => {
          setLoading(false)
        })
    } catch {}
  }
  // github第三方登录
  const githubHandler = () => {
    setLoading(true)
    githubAuthorization()
  }

  useEffect(() => {
    const query = qs.parse(location.search)
    const { token, state } = query
    if (Number(state) === 0) {
      message.error('授权失败，请重新登录~')
      return
    }
    if (token) {
      // redux-thunk:dispatch(函数)
      dispatch(loginByToken(token as string)).then(res => {
        // 检查是否为一个空的对象，类数组，map或者set
        if (!isEmpty(res.userInfo)) {
          history.replace(redirectUrl)
        }
      })
    }
    // 仅在依赖项发生变化时才会重新渲染，性能优化
    // 对于dispatch：为了安全，凡是在useEffect内用到的依赖项都要放在数组内
  }, [history, location.search, dispatch, redirectUrl])

  // 如果是开发环境，自动填入默认账号密码
  useEffect(() => {
    if (CONFIG.isDevelopment) {
      // 使用 form.setFieldsValue 来动态改变表单值
      form.setFieldsValue({
        loginName: 'test',
        password: '123456',
      })
    }
    // 只在组件挂载和卸载时执行
  }, [])
  return (
    <section className="login-page">
      <a
        href={CONFIG.github.repositoryUrl}
        target="_blank"
        rel="noopner noreferrer"
      >
        {/* 右上角 章鱼猫Octocat  octopus：章鱼 */}
        <svg
          className="svg-wrapper"
          width="56"
          height="56"
          viewBox="0 0 250 250"
        >
          <path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path>
          <path
            d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2"
            fill="currentColor"
            className="octo-arm"
          ></path>
          <path
            d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z"
            fill="currentColor"
          ></path>
        </svg>
      </a>

      <div className="main-container">
        <div>
          {/* logo + 文本 */}
          <div className="logo-wrap">
            <img className="logo" src={logo} alt="" />
            <em>Carefree Admin</em>
          </div>
          <Form form={form}>
            <Form.Item
              name="loginName"
              initialValue={LOGIN_NAME}
              rules={[
                {
                  required: true,
                  message: '请输入用户名',
                  whitespace: true,
                },
              ]}
            >
              <Input
                placeholder="用户名"
                prefix={<UserOutlined />}
                maxLength={32}
                allowClear
                autoFocus
                autoComplete="off"
                onPressEnter={handleSubmit}
              ></Input>
            </Form.Item>
            <Form.Item
              name="password"
              rules={[
                {
                  required: true,
                  message: '请输入密码',
                  whitespace: true,
                },
              ]}
            >
              <Input
                type="password"
                placeholder="密码"
                prefix={<LockOutlined />}
                maxLength={32}
                allowClear
                autoComplete="off"
                onPressEnter={handleSubmit}
              ></Input>
            </Form.Item>
            {/* `.`：匹配除换行符\n之外的任何单个字符 */}
            {/* {n}：n 是一个非负整数。匹配确定的 n 次。例如，'o{2}' 不能匹配 "Bob" 中的 'o'，但是能匹配 "food" 中的两个 o。 */}
            <Form.Item
              name="code"
              validateTrigger="onBlur"
              rules={[
                { required: true, message: '请输入验证码' },
                { pattern: /.{4}/, message: '请输入正确二维码' },
              ]}
            >
              {/* 随机字符验证码 */}
              <Input
                placeholder="请输入验证码"
                prefix={<PictureOutlined />}
                maxLength={4}
                autoComplete="off"
                onPressEnter={handleSubmit}
                suffix={
                  <img
                    className="captcha"
                    src={`https://work.xiejiahe.com/api/captcha?code=${captcha}`}
                    alt=""
                    onClick={reloadCaptcha}
                  />
                }
              ></Input>
            </Form.Item>
          </Form>
          <Button
            type="primary"
            style={{ marginTop: '20px' }}
            size="large"
            loading={loading}
            block
            onClick={handleSubmit}
          >
            {loading ? '登 录 中...' : '登 录'}
          </Button>
          {/* 注册 */}
          <div className="register">
            <Popover
              content={PopoverContent}
              trigger="hover"
              placement="bottomRight"
            >
              <span>注册账号</span>
            </Popover>
          </div>
          {/* 使用Github登录 */}
          <Button
            style={{ marginTop: '20px' }}
            size="large"
            loading={loading}
            icon={<GithubOutlined />}
            block
            onClick={githubHandler}
          >
            使用 Github 登录
          </Button>
        </div>
      </div>
      <Footer></Footer>
    </section>
  )
}

// 生成容器组件
export default connect()(Login)
